package com.hcss.common.util.excel;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;

import com.hcss.common.util.excel.rull.ExcelRullResult;
import com.hcss.common.util.excel.rull.RullType;
import com.hcss.common.util.excel.util.ExcelFileUtil;
import com.hcss.common.util.excel.util.ExcelReader;
import com.hcss.common.util.excel.util.ExcelWriter;

import lombok.extern.slf4j.Slf4j;

/**
 * @Description: 这个是真正开发使用的Excel工具类
 * @Author:momo
 * @Since:2018年12月21日
 * @Version:1.1.0
 */
@Slf4j
public class ExcelUtil {
	
	/**
	 * 创建Excel模板并写入指定输出流中
	 * @paramp isXlsx excel后缀是否为xlsx即07版本
	 * @param os 输出流
	 * @param header 模板名称
	 * @return
	 */
	public static boolean write2ExcelTemp(Iterable<String> header, OutputStream os, boolean isXlsx) {
		try {
			ExcelWriter writer = new ExcelWriter(os, isXlsx, "sheet1", null);
			writer.writeHeadRow(header);
			writer.close();
		}catch(IOException e) {
			log.error("IOEXCEPTION!",e); 
			return false;
		}
		return true;
	}
	
	/**
	 * 创建Excel并写入指定输出流中
	 * @param aliasName 标题别名 规则如下：<br>
	 * aliasName = [{age:年龄},{name:名称}] <br>
	 * 其中age位bean中的field，后边为别名，如果需要Excel列有顺序，则传入的Map使用LinkedHashMap
	 * @param dataList 每一列的数据，其中List中的数据可以为JavaBean 也可以为Map
	 * @paramp isXlsx excel后缀是否为xlsx即07版本
	 * @return
	 */
	public static boolean write2ExcelFromIo(Map<String, String> aliasName, List<?> dataList, OutputStream os, boolean isXlsx) {
		
		if(CollectionUtils.isEmpty(dataList)) {
			write2ExcelTemp(aliasName.values(),os,isXlsx);
		}
		
		try {
			ExcelWriter writer = new ExcelWriter(os, isXlsx, "sheet1", null);
			writer.setHeaderAlias(aliasName);
			writer.write(dataList);
			writer.close();
		}catch(IOException e) {
			log.error("IOEXCEPTION!",e); 
			return false;
		}
		return true;
	}
	
	/**
	 * 创建Excel并写入指定输出流中
	 * @param aliasName 标题别名 规则如下：<br>
	 * aliasName = [{age:年龄},{name:名称}] <br>
	 * 其中age位bean中的field，后边为别名，如果需要Excel列有顺序，则传入的Map使用LinkedHashMap
	 * @param dataList 每一列的数据，其中List中的数据可以为JavaBean 也可以为Map
	 * @param sheetName sheet名称
	 * @paramp password 密码不设定则为空 null
	 * @paramp isXlsx excel后缀是否为xlsx即07版本
	 * @return
	 */
	public static boolean write2ExcelFromIo(Map<String, String> aliasName, List<?> dataList, OutputStream os, String sheetName, String password, boolean isXlsx) {
		try {
			ExcelWriter writer = new ExcelWriter(os, isXlsx, sheetName, password);
			writer.setHeaderAlias(aliasName);
			writer.write(dataList);
			writer.close();
		}catch(IOException e) {
			log.error("IOEXCEPTION!",e); 
			return false;
		}
		return true;
	}
	
	/**
	 * 创建Excel并将指定数据写入Excel中
	 * @param aliasName 标题别名 规则如下：<br>
	 * aliasName = [{age:年龄},{name:名称}] <br>
	 * 其中age位bean中的field，后边为别名，如果需要Excel列有顺序，则传入的Map使用LinkedHashMap
	 * @param dataList 每一列的数据，其中List中的数据可以为JavaBean 也可以为Map
	 * @param destFile 创建并写入的文件
	 * @return
	 */
	public static boolean wiret2ExcelFile(Map<String, String> aliasName, List<?> dataList, File destFile) {
		return wiret2ExcelFile(aliasName, dataList, destFile, "sheet1", null);
	}
	
	
	/**
	 * 创建Excel并将指定数据写入Excel中
	 * @param aliasName 标题别名 规则如下：<br>
	 * aliasName = [{age:年龄},{name:名称}] <br>
	 * 其中age位bean中的field，后边为别名，如果需要Excel列有顺序，则传入的Map使用LinkedHashMap
	 * @param dataList 每一列的数据，其中List中的数据可以为JavaBean 也可以为Map
	 * @param destFile 创建并写入的文件
	 * @param sheetName sheet名称
	 * @return
	 */
	public static boolean wiret2ExcelFile(Map<String, String> aliasName, List<?> dataList, File destFile, String sheetName) {
		return wiret2ExcelFile(aliasName, dataList, destFile, sheetName, null);
	}
	
	
	/**
	 * 创建Excel并将指定数据写入Excel中
	 * @param aliasName 标题别名 规则如下：<br>
	 * aliasName = [{age:年龄},{name:名称}] <br>
	 * 其中age位bean中的field，后边为别名，如果需要Excel列有顺序，则传入的Map使用LinkedHashMap
	 * @param dataList 每一列的数据，其中List中的数据可以为JavaBean 也可以为Map
	 * @param destFile 创建并写入的文件
	 * @param sheetName sheet名称
	 * @param password Excel密码，如果不需要加密传入null即可
	 * @return
	 */
	public static boolean wiret2ExcelFile(Map<String, String> aliasName, List<?> dataList, File destFile, String sheetName, String password) {
		try {
			ExcelWriter writer = new ExcelWriter(destFile, sheetName, password);
			writer.setHeaderAlias(aliasName);
			writer.write(dataList);
			writer.close();
		}catch(IOException e) {
			log.error("IOEXCEPTION!",e); 
			return false;
		}
		return true;
	}
	
	
	
	/**
	 * Excel的读取，读取为指定BeanList
	 * @param aliasName 标题别名 规则如下：<br>
	 * aliasName = [{age:年龄},{name:名称}] <br>
	 * @param beanType 指定要返回的Bean类类型
	 * @param excelFilePath 需要读取的Excel文件地址
	 * @return 
	 */
	public static <T> List<T>  readFromExcelFile(Map<String, String> aliasName, Class<T> beanType, String excelFilePath) {
		return readFromExcelFile(aliasName, beanType, excelFilePath, true);
	}
	
	/**
	 * Excel的读取，读取为指定BeanList
	 * @param aliasName 标题别名 规则如下：<br>
	 * aliasName = [{年龄:age},{名称:name}] <br>
	 * @param beanType 指定要返回的Bean类类型
	 * @param excelFilePath 需要读取的Excel文件地址
	 * @param ignoreEmptyRow 是否忽略空行
	 * @return 
	 */
	public static <T> List<T> readFromExcelFile(Map<String, String> aliasName, Class<T> beanType, String excelFilePath, boolean ignoreEmptyRow) {
		return readFromExcelWithPsd(aliasName, beanType, excelFilePath, ignoreEmptyRow, null);
	}
	
	/**
	 * 带有密码的访问
	 * @param aliasName
	 * @param beanType
	 * @param excelFilePath
	 * @param ignoreEmptyRow
	 * @param password 密码，如果没有密码，则可以传null
	 * @return
	 */
	public static <T> List<T> readFromExcelWithPsd(Map<String, String> aliasName, Class<T> beanType, String excelFilePath, boolean ignoreEmptyRow, String password) {
		ExcelReader reader = new ExcelReader(ExcelFileUtil.touch(excelFilePath), 0, password);
		reader.setHeaderAlias(aliasName);
		reader.setIgnoreEmptyRow(ignoreEmptyRow);
		return reader.readAll(beanType);
	}
	
	/**
	 * Excel的流读取，读取为指定BeanList
	 * @param aliasName 标题别名 规则如下：<br>
	 * aliasName = [{年龄:age},{名称:name}] <br>
	 * @param beanType 指定要返回的Bean类类型
	 * @param excelFilePath 需要读取的Excel文件地址
	 * @param ignoreEmptyRow 是否忽略空行
	 * @return 
	 */
	public static <T> List<T> readFromInputStream(Map<String, String> aliasName, Class<T> beanType, InputStream is) {
		return readFromInputStream(aliasName, beanType, is,true, null);
	}
	
	/**
	 * Excel的流读取，读取为指定BeanList
	 * @param aliasName 标题别名 规则如下：<br>
	 * aliasName = [{年龄:age},{名称:name}] <br>
	 * @param beanType 指定要返回的Bean类类型
	 * @param excelFilePath 需要读取的Excel文件地址
	 * @param ignoreEmptyRow 是否忽略空行
	 * @return 
	 */
	public static <T> List<T> readFromInputStream(Map<String, String> aliasName, Class<T> beanType, InputStream is, boolean ignoreEmptyRow) {
		return readFromInputStream(aliasName, beanType, is,ignoreEmptyRow, null);
	}
	
	/**
	 * Excel的流读取，读取为指定BeanList
	 * @param aliasName 标题别名 规则如下：<br>
	 * aliasName = [{年龄:age},{名称:name}] <br>
	 * @param beanType 指定要返回的Bean类类型
	 * @param excelFilePath 需要读取的Excel文件地址
	 * @param ignoreEmptyRow 是否忽略空行
	 * @return 
	 */
	public static <T> List<T> readFromInputStream(Map<String, String> aliasName, Class<T> beanType, InputStream is, boolean ignoreEmptyRow, String password) {
		ExcelReader reader = new ExcelReader(is, 0, password);
		reader.setHeaderAlias(aliasName);
		reader.setIgnoreEmptyRow(ignoreEmptyRow);
		return reader.readAll(beanType);
	}
	
	
	/** 带有校验类型的Read */
	/**
	 * Excel的流读取，读取为指定BeanList
	 * @param aliasName 标题别名 规则如下：<br>
	 * aliasName = [{年龄:age},{名称:name}] <br>
	 * 
	 * @param rullMap 规则列表 ,规则如下<br>
	 * rullMap = [{age : new NotNullRullType()}] , key为要设定规则的列名，后边为要设定的具体规则
	 * @param beanType 指定要返回的Bean类类型
	 * @param excelFilePath 需要读取的Excel文件地址
	 * @param ignoreEmptyRow 是否忽略空行
	 * @return 
	 */
	public static <T> ExcelRullResult<?> readFromInputStreamWithRull(Map<String, String> aliasName,Map<String, RullType> rullMap, Class<T> beanType, InputStream is, boolean ignoreEmptyRow, String password) throws Exception {
		if(null == aliasName || null == rullMap) {
			throw new Exception("别名与规则列表不能为空！");
		}
		
		ExcelReader reader = new ExcelReader(is, 0, password);
		reader.setHeaderAlias(aliasName);
		reader.setIgnoreEmptyRow(ignoreEmptyRow);
		reader.setRullMap(rullMap);
		return reader.readAllWithRull(beanType);
	}
	
	
	
	
	
	
}

    